package com.file.parser.socialsecurity;


import com.file.bo.ResponseData;
import com.file.bo.socialsecurity.JilinInsuranceParticipation;
import com.file.constant.ErrorCode;
import com.file.parser.BasePdfParser;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class JilinSocialSecurityPdfParser extends BasePdfParser {

    public ResponseData<String> parseJilinSocialSecurityPdfToJson(String daId, String filePath) {
        log.info("parseJilinSocialSecurityPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            //吉林社保和参保证明是同一个文件
            if (filePath.contains("cbzm")) {
                JilinInsuranceParticipation jilinInsuranceParticipation = parseJilinInsuranceParticipation(filePath, daId);
                json = JsonUtils.convertObjectToJson(jilinInsuranceParticipation);
            } else if (filePath.contains("qyd")) {//NOSONAR
                JilinInsuranceParticipation jilinInsuranceParticipation = parseJilinInsuranceParticipation(filePath, daId);
                json = JsonUtils.convertObjectToJson(jilinInsuranceParticipation);
            } else {
                log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseJilinSocialSecurityPdfToJson failed, new type not supported");
                return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseJilinSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseJilinSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private JilinInsuranceParticipation parseJilinInsuranceParticipation(String filePath, String daId) {
        JilinInsuranceParticipation jilinInsuranceParticipation = parseJilinInsuranceParticipationHeader(filePath, daId);
        List<List<String>> rowList = parseFileToRowList(filePath);
//        for (List<String> cellList : rowList) {
//            System.out.println(cellList);
//        }

        parseListToBO(rowList, jilinInsuranceParticipation);
        return jilinInsuranceParticipation;
    }

    private JilinInsuranceParticipation parseJilinInsuranceParticipationHeader(String filePath, String daId) { //NOSONAR
        JilinInsuranceParticipation jilinInsuranceParticipation = new JilinInsuranceParticipation();
        String pdfText = parsePdfHeaderText(filePath)
                .replace(System.getProperty("line.separator", "\n"), StringUtils.EMPTY);

        String accountType = parsePdfHeaderField(pdfText, "账户类别:|姓  名");
        String warmTips = parsePdfHeaderField(pdfText, "【温馨提示】|吉林省社会保险事业管理局制");
        String handler = parsePdfHeaderField(pdfText, "局制经办人：| 经办时间 ");
        String handlingTime = parsePdfHeaderField(pdfText, "公服 经办时间|打印时间");
        String printTime = parsePdfHeaderField(pdfText, "打印时间");
        String retireUnit = parsePdfHeaderField(pdfText, "退休单位:|险  种 离退休时间(失业时间)");
        jilinInsuranceParticipation.setAccountType(accountType);
        jilinInsuranceParticipation.setWarmTips(warmTips);
        jilinInsuranceParticipation.setHandler(handler);
        jilinInsuranceParticipation.setHandlingTime(handlingTime);
        jilinInsuranceParticipation.setPrintTime(printTime);
        JilinInsuranceParticipation.BenefitReceiptSituation benefitReceiptSituation = new JilinInsuranceParticipation.BenefitReceiptSituation();
        benefitReceiptSituation.setRetireUnit(retireUnit);
        jilinInsuranceParticipation.setBenefitReceiptSituation(benefitReceiptSituation);

        return  jilinInsuranceParticipation;
    }

    private void parseListToBO(List<List<String>> rowList, JilinInsuranceParticipation jilinInsuranceParticipation) {
        JilinInsuranceParticipation.PersonalBasicInformation personalBasicInformation = new JilinInsuranceParticipation.PersonalBasicInformation();
        List<JilinInsuranceParticipation.BenefitReceiptSituationRecord> benefitReceiptSituationRecordList = new ArrayList<>();
        JilinInsuranceParticipation.BenefitReceiptSituation benefitReceiptSituation = jilinInsuranceParticipation.getBenefitReceiptSituation();
        benefitReceiptSituation.setBenefitReceiptSituationRecordList(benefitReceiptSituationRecordList);
        List<JilinInsuranceParticipation.InsurancePaymentSituation> insurancePaymentSituationList = new ArrayList<>();

        String sectionName = "";

        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "姓  名")) {
                sectionName = "姓名";
            } else if (StringUtils.equals(cellList.get(0), "性  别")) {
                sectionName = "性别";
            } else if (StringUtils.equals(cellList.get(0), "生存状态")) {
                sectionName = "生存状态";
            } else if (StringUtils.equals(cellList.get(1), "缴费状态")) {
                sectionName = "缴费状态";
                continue;
            } else if (StringUtils.equals(cellList.get(1), "离退休时间(失业时间)")) {
                sectionName = "离退休时间";
                continue;
            } else if (StringUtils.equals(cellList.get(1), "失业时间")) {
                sectionName = "失业时间";
                continue;
            } else if (StringUtils.equals(cellList.get(1), "应享月数")) {
                sectionName = "应享月数";
                continue;
            }
            switch (sectionName) { //NOSONAR
                case "姓名":
                    personalBasicInformation.setName(cellList.get(1));
                    personalBasicInformation.setIdType(cellList.get(3));
                    personalBasicInformation.setIdNo(cellList.get(5));
                    break;
                case "性别":
                    personalBasicInformation.setGender(cellList.get(1));
                    personalBasicInformation.setBirthDate(cellList.get(3));
                    personalBasicInformation.setPersonalId(cellList.get(5));
                    break;
                case "生存状态":
                    personalBasicInformation.setSurvivalStatus(cellList.get(1));
                    personalBasicInformation.setEmploymentDate(cellList.get(3));
                    break;
                case "缴费状态":
                    JilinInsuranceParticipation.InsurancePaymentSituation insurancePaymentSituation = new JilinInsuranceParticipation.InsurancePaymentSituation();
                    insurancePaymentSituation.setInsuranceType(cellList.get(0));
                    insurancePaymentSituation.setPaymentStatus(cellList.get(1));
                    insurancePaymentSituation.setInsuredUnitName(cellList.get(2));
                    insurancePaymentSituation.setInsuranceTime(cellList.get(3));
                    insurancePaymentSituation.setPaymentRecordStartTime(cellList.get(4));
                    insurancePaymentSituation.setPaymentRecordEndTime(cellList.get(5));
                    insurancePaymentSituation.setActualPaymentMonths(cellList.get(6));
                    insurancePaymentSituationList.add(insurancePaymentSituation);
                    break;
                case "离退休时间":
                case "失业时间":
                    JilinInsuranceParticipation.BenefitReceiptSituationRecord benefitReceiptSituationRecord = new JilinInsuranceParticipation.BenefitReceiptSituationRecord();
                    benefitReceiptSituationRecord.setInsuranceType(cellList.get(0));
                    benefitReceiptSituationRecord.setRetirementDate(cellList.get(1));
                    benefitReceiptSituationRecord.setBenefitReceiptStartTime(cellList.get(2));
                    benefitReceiptSituationRecord.setBenefitReceiptEndTime(cellList.get(3));
                    benefitReceiptSituationRecord.setIssuingStatus(cellList.get(4));
                    benefitReceiptSituationRecord.setCurrentBenefitAmount(cellList.get(5));
                    benefitReceiptSituationRecordList.add(benefitReceiptSituationRecord);
                    break;
                case "应享月数":
                    benefitReceiptSituation.setBenefitType(cellList.get(0));
                    benefitReceiptSituation.setEntitledMonths(cellList.get(1));
                    benefitReceiptSituation.setReceivedMonths(cellList.get(2));
                    benefitReceiptSituation.setRemainingMonths(cellList.get(3));
                    benefitReceiptSituation.setTerminationReason(cellList.get(4));
                    benefitReceiptSituation.setTerminationHandlingTime(cellList.get(5));
                    break;
            }
        }

        jilinInsuranceParticipation.setPersonalBasicInformation(personalBasicInformation);
        jilinInsuranceParticipation.setInsurancePaymentSituationList(insurancePaymentSituationList);
        jilinInsuranceParticipation.setBenefitReceiptSituation(benefitReceiptSituation);
    }

    private List<List<String>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
                rectangle.setBottom(rectangle.getBottom());
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    public static void main(String[] args) {
        String filePath = "D:\\data\\file\\socialsecurity\\吉林\\吉林1\\app-gjzwfw-dzsb_cbzm.pdf";
        JilinSocialSecurityPdfParser jilinSocialSecurityPdfParser = new JilinSocialSecurityPdfParser();
        String json = jilinSocialSecurityPdfParser.parseJilinSocialSecurityPdfToJson("", filePath).getData();
        System.out.println(json);
    }

}
